package com.swt.gap.service.impl;

import com.swt.gap.common.graph.Graph;
import com.swt.gap.config.ServerConfig;
import com.swt.gap.dao.OntologyNodeDao;
import com.swt.gap.dao.SysIconMapper;
import com.swt.gap.model.entity.OntologyNode;
import com.swt.gap.model.entity.SysIcon;
import com.swt.gap.model.vo.element.*;
import com.swt.gap.service.EventElementService;
import com.swt.gap.service.TextDataService;
import com.swt.gap.util.UserLoginUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 请填写说明
 *
 * @author sx
 * @date 2020/9/4 10:14
 */
@Service
public class TextDataServiceImpl implements TextDataService {


    public static final String STATUS_FAILURE = "failure";
    public static final String PROPERTY_NAME = "名称";


    @Value("${extract.event}")
    private String extractUrl;

    private final RestTemplate restTemplate;
    private final OntologyNodeDao ontologyNodeDao;
    private final EventElementService eventElementService;
    private final ServerConfig serverConfig;
    private final SysIconMapper sysIconMapper;

    public TextDataServiceImpl(RestTemplate restTemplate,
                               OntologyNodeDao ontologyNodeDao,
                               EventElementService eventElementService,
                               ServerConfig serverConfig,
                               SysIconMapper sysIconMapper) {
        this.restTemplate = restTemplate;
        this.ontologyNodeDao = ontologyNodeDao;
        this.eventElementService = eventElementService;
        this.serverConfig = serverConfig;
        this.sysIconMapper = sysIconMapper;
    }

    @Override
    public ElementParseVO extractCombinedEvents(String text) {
        Integer userId = UserLoginUtils.getUserId();
        ElementParseVO elementParseVO = new ElementParseVO();

//        String url="http://ws.nju.edu.cn/ila/extract";
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        //定义body里的传参
        HashMap<String, Object> bodyMap = new HashMap<>();
        // id为任意字符串，用来区分不同的请求
        bodyMap.put("id", new Random(1).nextInt(100));
        // 要做信息抽取的文段，可以包含多个段落
        bodyMap.put("text",text);
        HttpEntity<Map<String, Object>> entity = new HttpEntity<>(bodyMap, headers);
        CombinedResult combinedResult = restTemplate.postForEntity(extractUrl, entity, CombinedResult.class).getBody();
        elementParseVO.setCombinedResult(combinedResult);


        //获取列表展示结果
        List<ElementParseVO.EventExtractVO> eventExtracts = new ArrayList<>();
        //获取所有的事件类型
        ontologyNodeDao.selectByType(2).forEach(ontologyEntity -> {
            ElementParseVO.EventExtractVO eventExtractVO = new ElementParseVO.EventExtractVO();
            eventExtractVO.setEventTypeId(ontologyEntity.getNodeId());
            eventExtractVO.setEventTypeName(StringUtils.substringAfterLast(ontologyEntity.getLabels(), ","));
            eventExtractVO.setElementVOS(eventElementService.AllElements(ontologyEntity.getNodeId(), userId));
            int count = 0;
            eventExtractVO.setCount(count);
            List<ElementParseVO.EventExtractVO.EventList> eventLists = new ArrayList<>();
            eventExtractVO.setEventLists(eventLists);
            eventExtracts.add(eventExtractVO);
        });

        assert combinedResult != null;
        ResultsBean results = combinedResult.getResults();
        String status = combinedResult.getStatus();
        //提取失败或者没内容时 返回null
        if (null == results || STATUS_FAILURE.equals(status) || results.getCombined_events().isEmpty()) {
//            List<ElementParseVO.EventExtractVO> eventExtract = this.createDefaultForm();
//            elementParseVO.setEventExtractVOS(eventExtract);
//            return elementParseVO;
            return null;
        }


        List<ResultsBean.CombinedEventsBean> combinedEvents = results.getCombined_events();

        for (ResultsBean.CombinedEventsBean combinedEvent : combinedEvents) {
            //获取事件子类型英文简称,事件名，触发词，事件论元
            String eventName = combinedEvent.getName();
            String subtype = combinedEvent.getSubtype();
            String subtypeCn = combinedEvent.getSubtype_cn();
            List<ResultsBean.CombinedEventsBean.CombinedArgumentsBean> combinedArguments = combinedEvent.getCombined_arguments();
            //判断论元和事件名称是否为空
            if (!StringUtils.isEmpty(eventName) || !CollectionUtils.isEmpty(combinedArguments)) {
                OntologyNode ontologyNode = ontologyNodeDao.selectByEnglishName(subtype);
                if (ontologyNode != null) {
                    String eventTypeName = StringUtils.substringAfterLast(ontologyNode.getLabels(), ",");
                    //以事件类型区分
                    eventExtracts.forEach(eventExtractVO -> {
                        if (eventExtractVO.getEventTypeName().equals(eventTypeName)) {
                            eventExtractVO.setCount(eventExtractVO.getCount() + 1);

                            ElementParseVO.EventExtractVO.EventList eventList = new ElementParseVO.EventExtractVO.EventList();
                            if (!StringUtils.isEmpty(eventName)) {
                                eventList.setEventName(eventName);
                            } else {
                                eventList.setEventName(subtypeCn);
                            }

                            List<String> header = new ArrayList<>();
                            List<EventElementVO> elements = eventExtractVO.getElementVOS();
                            elements.forEach(eventElementVO -> header.add(eventElementVO.getElement()));
                            eventList.setHeader(header);

                            List<EventContentVO> eventContents = new ArrayList<>();
                            for (int i = 0; i < header.size(); i++) {
                                List<ContentVO> contents = new ArrayList<>();
                                if (header.get(i).equals(PROPERTY_NAME)) {
                                    ContentVO contentVO = new ContentVO();
                                    contentVO.setContent(eventList.getEventName());
                                    contents.add(contentVO);
                                }
                                EventContentVO eventContentVO = new EventContentVO();
                                eventContentVO.setIndex(i);
                                eventContentVO.setContentVOS(contents);
                                eventContents.add(eventContentVO);
                            }

                            combinedArguments.forEach(argumentMentionsBean -> {
                                String role = argumentMentionsBean.getRole();
                                AtomicReference<String> roleCn = new AtomicReference<>("");
                                elements.forEach(eventElementVO -> {
                                    String englishName = eventElementVO.getEnglishName();
                                    if (!StringUtils.isEmpty(englishName)) {
                                        if (role.equals(englishName)) {
                                            roleCn.set(eventElementVO.getElement());
                                        }

                                    }
                                });

                                for (int i = 0; i < header.size(); i++) {
                                    for (EventContentVO eventContentVO : eventContents) {
                                        if (eventContentVO.getIndex() == i) {
                                            if (header.get(i).equals(roleCn.get())) {
                                                ContentVO contentVO = new ContentVO();
                                                contentVO.setContent(argumentMentionsBean.getNormalization() == null ? argumentMentionsBean.getText() : argumentMentionsBean.getNormalization());
                                                contentVO.setBegin(argumentMentionsBean.getBegin());
                                                contentVO.setEnd(argumentMentionsBean.getEnd());
                                                List<ContentVO> contentVOS = eventContentVO.getContentVOS();
                                                contentVOS.add(contentVO);
                                                eventContentVO.setContentVOS(contentVOS);
                                            }
                                        }
                                    }
                                }
                            });

                            eventList.setEventContentVOS(eventContents);

                            List<ElementParseVO.EventExtractVO.EventList> eventLists = eventExtractVO.getEventLists();
                            eventLists.add(eventList);
                            eventExtractVO.setEventLists(eventLists);
                        }
                    });
                }
            }
        }



        //剔除掉事件数量为0的事件类型
        List<ElementParseVO.EventExtractVO> extracts = new ArrayList<>();
        //供选择的事件类型列表
        List<ElementParseVO.EventExtractVO> otherEventTypes = new ArrayList<>();
        for (ElementParseVO.EventExtractVO eventExtractVO : eventExtracts) {
            if (eventExtractVO.getCount() != 0) {
                extracts.add(eventExtractVO);
            } else {
                otherEventTypes.add(eventExtractVO);
            }
        }
        elementParseVO.setEventExtractVOS(extracts);

        elementParseVO.setOtherEventExtract(otherEventTypes);

        return elementParseVO;
    }

    @Override
    public Graph generateGraph(List<ElementParseVO.EventExtractVO> eventExtracts, String savedFileName) {
        String fileName = savedFileName.substring(savedFileName.lastIndexOf("_") + 1);
        //建图数据
        List<Graph.Node> nodes = new ArrayList<>();
        List<Graph.Link> links = new ArrayList<>();
        //文本节点
        Graph.Node fileNode = new Graph.Node();
        fileNode.setName(fileName);
        fileNode.setId(UUID.randomUUID().toString());
        fileNode.setIcon(serverConfig.parseViewUrl("hg-task-file.png", 3));
        nodes.add(fileNode);

        eventExtracts.forEach(eventExtractVO -> {
            //事件类型节点
            Graph.Node entityLabelNode = new Graph.Node();
            entityLabelNode.setName(eventExtractVO.getEventTypeName());
            entityLabelNode.setId(UUID.randomUUID().toString());
            if (eventExtractVO.getEventTypeId() != null) {
                OntologyNode ontologyNode = ontologyNodeDao.selectByPrimaryKey(eventExtractVO.getEventTypeId());
                SysIcon sysIcon = sysIconMapper.selectByPrimaryKey(ontologyNode.getIconId());
                entityLabelNode.setIcon(serverConfig.parseViewUrl(sysIcon.getIconFile(), 3));
            } else {
                entityLabelNode.setIcon(serverConfig.parseViewUrl("hg-event-element.png", 3));
            }

            nodes.add(entityLabelNode);

            Graph.Link link = new Graph.Link();
            link.setId(UUID.randomUUID().toString());
            link.setStartNodeId(fileNode.getId());
            link.setEndNodeId(entityLabelNode.getId());
            links.add(link);

            //要素类型节点
            for (int i = 0; i < eventExtractVO.getElementVOS().size(); i++) {
                EventElementVO eventElementVO = eventExtractVO.getElementVOS().get(i);
                Graph.Node elementLabelNode = new Graph.Node();
                elementLabelNode.setName(eventElementVO.getElement());
                elementLabelNode.setId(UUID.randomUUID().toString());
                elementLabelNode.setIcon(serverConfig.parseViewUrl("hg-event-element.png", 3));
                nodes.add(elementLabelNode);

                Graph.Link elementLink = new Graph.Link();
                elementLink.setId(UUID.randomUUID().toString());
                elementLink.setStartNodeId(entityLabelNode.getId());
                elementLink.setEndNodeId(elementLabelNode.getId());
                links.add(elementLink);

                //事件节点
                for (int k = 0; k < eventExtractVO.getEventLists().size(); k++) {
                    ElementParseVO.EventExtractVO.EventList eventList = eventExtractVO.getEventLists().get(k);
                    List<EventContentVO> eventContents = eventList.getEventContentVOS();
                    if (!CollectionUtils.isEmpty(eventContents)) {

                        for (int n = 0; n < eventList.getHeader().size(); n++) {
                            String header = eventList.getHeader().get(n);
                            for (EventContentVO eventContentVO : eventContents) {
                                if (eventContentVO.getIndex() == n && header.equals(eventElementVO.getElement())) {
                                    if (!CollectionUtils.isEmpty(eventContentVO.getContentVOS())) {
                                        for (ContentVO contentVO : eventContentVO.getContentVOS()) {
                                            Graph.Node eventNode = new Graph.Node();
                                            eventNode.setName(contentVO.getContent());
                                            eventNode.setId(UUID.randomUUID().toString());
                                            eventNode.setIcon(serverConfig.parseViewUrl("hg-event-element.png", 3));
                                            nodes.add(eventNode);

                                            Graph.Link eventLink = new Graph.Link();
                                            eventLink.setId(UUID.randomUUID().toString());
                                            eventLink.setStartNodeId(elementLabelNode.getId());
                                            eventLink.setEndNodeId(eventNode.getId());
                                            links.add(eventLink);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        });

        return new Graph(nodes, links);
    }
}
